package com.broada.apm.indicator.api.util;


import java.io.Serializable;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import org.apache.commons.lang.StringUtils;

public class DateUtil implements Cloneable, Serializable {
	private static final long serialVersionUID = -4791944744877480675L;
	public static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static final SimpleDateFormat TIME_FORMAT_MINUTE = new SimpleDateFormat("yyyy-MM-dd HH:mm");

	public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

	public static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");

	public static final SimpleDateFormat DATETIME_NOTSPLIT_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");

	public static int SUNDAY = 1;

	public static int MONDAY = 2;

	public static int TUESDAY = 3;

	public static int WEDNESDAY = 4;

	public static int THURSDAY = 5;

	public static int FRIDAY = 6;

	public static int SATURDAY = 0;

	public static String[] WEEKNAME = { "日", "一", "二", "三", "四", "五", "六" };
	
	public static final String STEP_SECOND = "_s";
	public static final String STEP_MINUTE = "_m";
	public static final String STEP_HOUR = "_h";
	public static final String STEP_DAY = "_d";
	public static final String STEP_WEEK = "_w";
	public static final String STEP_MONTH = "_M";
	public static final String STEP_YEAR = "_y";

	private int day;
	private int month;
	private int year;
	
	public DateUtil() {
		GregorianCalendar todaysDate = new GregorianCalendar();
		this.year = todaysDate.get(1);
		this.month = (todaysDate.get(2) + 1);
		this.day = todaysDate.get(5);
	}

	public DateUtil(int yyyy, int mm, int dd) {
		this.year = yyyy;
		this.month = mm;
		this.day = dd;
		if (!(isValid()))
			throw new IllegalArgumentException();
	}

	public DateUtil(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		this.year = c.get(1);
		this.month = (c.get(2) + 1);
		this.day = c.get(5);
	}

	private boolean isValid() {
		DateUtil t = new DateUtil();
		t.fromJulian(toJulian());
		return ((t.day == this.day) && (t.month == this.month) && (t.year == this.year));
	}

	private int toJulian() {
		int jy = this.year;
		if (this.year < 0) {
			++jy;
		}
		int jm = this.month;
		if (this.month > 2) {
			++jm;
		} else {
			--jy;
			jm += 13;
		}
		int jul = (int) (Math.floor(365.25D * jy) + Math.floor(30.600100000000001D * jm) + this.day + 1720995.0D);
		int IGREG = 588829;

		if (this.day + 31 * (this.month + 12 * this.year) >= IGREG) {
			int ja = (int) (0.01D * jy);
			jul += 2 - ja + (int) (0.25D * ja);
		}
		return jul;
	}

	private void fromJulian(int j) {
		int ja = j;
		int JGREG = 2299161;

		if (j >= JGREG) {
			int jalpha = (int) ((j - 1867216 - 0.25D) / 36524.25D);
			ja += 1 + jalpha - (int) (0.25D * jalpha);
		}
		int jb = ja + 1524;
		int jc = (int) (6680.0D + (jb - 2439870 - 122.09999999999999D) / 365.25D);
		int jd = (int) (365 * jc + 0.25D * jc);
		int je = (int) ((jb - jd) / 30.600100000000001D);
		this.day = (jb - jd - (int) (30.600100000000001D * je));
		this.month = (je - 1);
		if (this.month > 12) {
			this.month -= 12;
		}
		this.year = (jc - 4715);
		if (this.month > 2) {
			this.year -= 1;
		}
		if (this.year <= 0)
			this.year -= 1;
	}

	public static int getMonthLastDay(int year, int month) {
		Calendar c = Calendar.getInstance();
		if (month < 12)
			c.set(year, month, 1);
		else {
			c.set(year + 1, 1, 1);
		}
		c.add(5, -1);
		return c.get(5);
	}

	public static String getNowTime() {
		return new Timestamp(new Date().getTime()).toString().substring(0, 19);
	}
	public static long getTimestamp() {
		return new Date().getTime();
	}
	public static Date getDayStart() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(11, 0);
		cal.set(12, 0);
		cal.set(13, 0);
		cal.set(14, 0);
		return cal.getTime();
	}

	public static Date getDayEnd() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(11, 23);
		cal.set(12, 59);
		cal.set(13, 59);
		cal.set(14, 999);
		return cal.getTime();
	}

	public static Date getYesterdayEnd() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(5, cal.get(5) - 1);
		cal.set(11, 23);
		cal.set(12, 59);
		cal.set(13, 59);
		cal.set(14, 999);
		return cal.getTime();
	}

	public static Date getWeekStart() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(7, 2);
		cal.set(11, 0);
		cal.set(12, 0);
		cal.set(13, 0);
		cal.set(14, 0);
		return cal.getTime();
	}

	public static Date getWeekEnd() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(7, 7);
		cal.add(5, 1);
		cal.set(11, 23);
		cal.set(12, 59);
		cal.set(13, 59);
		cal.set(14, 999);
		return cal.getTime();
	}

	public static Date getMonthStart() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(5, 1);
		cal.set(11, 0);
		cal.set(12, 0);
		cal.set(13, 0);
		cal.set(14, 0);
		return cal.getTime();
	}

	public static Date getMonthEnd() {
		Calendar cal = GregorianCalendar.getInstance();
		cal.set(5, cal.getActualMaximum(5));
		cal.set(11, 23);
		cal.set(12, 59);
		cal.set(13, 59);
		cal.set(14, 999);
		return cal.getTime();
	}

	public static Date parseDate(String dateStr, String timeStr, SimpleDateFormat formater) throws ParseException {
		if ((dateStr == null) || (dateStr.trim().length() < 4)) {
			return null;
		}
		if (timeStr == null) {
			timeStr = "";
		}
		if ((dateStr.length() < 11) && (timeStr.trim().length() > 0)) {
			dateStr = dateStr + " " + timeStr;
		}
		if (formater == null) {
			if (dateStr.length() > 10)
				formater = DATETIME_FORMAT;
			else {
				formater = DATE_FORMAT;
			}
		}
		return formater.parse(dateStr);
	}

	public static Date parseDate(String dateStr, String timeStr) throws ParseException {
		return parseDate(dateStr, timeStr, null);
	}

	public void setDate(int yyyy, int mm, int dd) {
		this.year = yyyy;
		this.month = mm;
		this.day = dd;
	}

	public void setDate(String yyyy, String mm, String dd) {
		try {
			setDate(Integer.parseInt(yyyy), Integer.parseInt(mm), Integer.parseInt(dd));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public int getDay() {
		return this.day;
	}

	public int getMonth() {
		return this.month;
	}

	public int getYear() {
		return this.year;
	}

	public static String formatDate(Date date, String format) {
		if (date == null) {
			return "";
		}
		return new SimpleDateFormat(format).format(date);
	}

	public String toString() {
		return "Day[" + this.year + "," + this.month + "," + this.day + "]";
	}

	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
		}
		return null;
	}

	public boolean equals(Object obj) {
		if (!(super.getClass().equals(obj.getClass()))) {
			return false;
		}
		DateUtil b = (DateUtil) obj;
		return ((this.day == b.day) && (this.month == b.month) && (this.year == b.year));
	}
	
	@SuppressWarnings("deprecation")
	/**
	 * 计算时间段
	 * 传入起始时间和结束时间和步进，返回一个时间的列表
	 */
	public static List<Date> getDateArray(Date start, Date end, String stepLength) {
		if (StringUtils.isBlank(stepLength) || (!STEP_SECOND.equals(stepLength) && !STEP_MINUTE.equals(stepLength)
				&& !STEP_HOUR.equals(stepLength) && !STEP_DAY.equals(stepLength) && !STEP_WEEK.equals(stepLength)
				&& !STEP_MONTH.equals(stepLength) && !STEP_YEAR.equals(stepLength))) {
			throw new IllegalArgumentException();
		}
		List<Date> dates = new ArrayList<Date>();
		dates.add(end);

		if (start.before(end)) {
			Date date = new Date(start.getTime());
			while (date.before(end)) {
				Date newDate = new Date(date.getTime());
				dates.add(newDate);

				switch (stepLength) {
				case STEP_SECOND:
					date.setSeconds(date.getSeconds() + 1);
					break;
				case STEP_MINUTE:
					date.setMinutes(date.getMinutes() + 1);
					break;
				case STEP_HOUR:
					date.setHours(date.getHours() + 1);
					break;
				case STEP_DAY:
					date.setDate(date.getDate() + 1);
					break;
				case STEP_WEEK:
					date.setDate(date.getDate() + 7);
					break;
				case STEP_MONTH:
					date.setMonth(date.getMonth() + 1);
					break;
				case STEP_YEAR:
					date.setYear(date.getYear() + 1);
					break;
				}
			}
		}

		return dates;
	}

}
